import { LAYER_CHANGE_TYPE } from "../common/GameConfig";
import LayerStatic from "../common/LayerStatic";
import { SoundManager, SoundName } from "../common/SoundManager";
import Utils from "../core/Utils";
import EventManager from "../core/event/EventManager";
import { Event_Name } from "../core/event/event_mgr";
import SDKHelper from "../core/sdk/SDKHelper";
import Block from "./Block";

const { ccclass, property } = cc._decorator;

@ccclass
export default class Game extends cc.Component {

    @property(cc.Prefab)
    gridPre: cc.Prefab = null;
    @property(cc.Node)
    mapArea: cc.Node = null;
    @property(cc.SpriteAtlas)
    skinList: cc.SpriteAtlas = null;
    @property(cc.Node)
    recycleBoard: cc.Node = null;
    @property(cc.Node)
    gameoverLayer: cc.Node = null;
    //全屏遮罩，洗牌过程中用
    @property(cc.Node)
    mask: cc.Node = null;
    //用于洗牌的节点
    @property(cc.Node)
    shuffleNode: cc.Node = null;
    //缓存区（拿出三块的道具）
    @property(cc.Node)
    bufferArea: cc.Node = null;
    @property(cc.Sprite)
    levelLog: cc.Sprite = null;
    @property(cc.Node)
    DifficultyTxtNode: cc.Node = null
    //关卡图片
    @property([cc.SpriteFrame])
    levelFrames: cc.SpriteFrame[] = [];
    //计数文本
    @property(cc.Label)
    countTxt: cc.Label = null;
    @property(cc.Node)
    propBtnList: cc.Node = null;
    //测试用 --yyyy
    @property(cc.Graphics)
    pencile: cc.Graphics = null;


    public recyclePoint: cc.Vec2;
    public levelLogoPosY: number;
    public isCanRevocation: boolean;
    public blockDataList = [];
    public blockNodeList: cc.Node[][];
    public totalBlockNum: number;
    public removeBlockNum: number;
    public isGameOver: boolean;
    public bufferList = [];
    public coverMap: number[][];
    public lastBlockIndex: number;
    public recycleList: Block[];
    public basePoint: cc.Vec2;

    onLoad() {
        LayerStatic.Instance.setGameStatic(this);
        this.initLevelData();
    }

    onEnable() {

    }

    onDestroy() {
        LayerStatic.Instance.setGameStatic(null);
    }

    start() {
        //设置方块回收的基准点
        this.recyclePoint = cc.v2(-3 * (this.gridPre.data.width + globalThis.GAME_GLOBAL.placeGap), 10);
        this.levelLogoPosY = this.levelLog.node.getPosition().y;
    }

    initLevelData() {
        console.log("当前关卡", globalThis.GAME_GLOBAL.levelGrade - 1);

        this.levelLog.spriteFrame = this.levelFrames[globalThis.GAME_GLOBAL.levelGrade - 1];

        let txtName = '';
        if (globalThis.GAME_GLOBAL.levelGrade === 1) {
            txtName = 'levelData_001';
        } else if (globalThis.GAME_GLOBAL.levelGrade <= 10) {
            // let ran = Utils.Instance.getRandomInt(8, 18);
            // let str = ran >= 10 ? ran : '0' + ran;
            let str: number = 1106
            str += globalThis.GAME_GLOBAL.levelGrade;
            txtName = 'levelData_' + str;

        }
        console.log("当前关卡：", txtName)
        //加载关卡数据
        Utils.Instance.loadSingleRes("levelTxtData/" + txtName, cc.TextAsset, (res) => {
            if (!res) return;
            globalThis.GAME_GLOBAL.levelData = JSON.parse(res.text);
            this.initGame();
        })
    }
    /** 选关 */
    initLevelData1() {
        console.log("当前关卡", globalThis.GAME_GLOBAL.levelGrade - 1);

        this.levelLog.spriteFrame = this.levelFrames[globalThis.GAME_GLOBAL.levelGrade - 1];

        let txtName = '';
        if (globalThis.GAME_GLOBAL.levelGrade === 1) {
            txtName = 'levelData_001';
        } else if (globalThis.GAME_GLOBAL.levelGrade <= 10) {
            // let ran = Utils.Instance.getRandomInt(8, 18);
            // let str = ran >= 10 ? ran : '0' + ran;
            let str: number = 1106
            str += globalThis.GAME_GLOBAL.levelGrade;
            txtName = 'levelData_' + str;

        }
        console.log("当前关卡：", txtName)
        //加载关卡数据
        Utils.Instance.loadSingleRes("levelTxtData/" + txtName, cc.TextAsset, (res) => {
            if (!res) return;
            globalThis.GAME_GLOBAL.levelData = JSON.parse(res.text);
            this.initGame();
        })
    }

    initGame() {
        this.isCanRevocation = true;
        this.propBtnList.active = globalThis.GAME_GLOBAL.levelGrade > 1;
        this.propBtnList.children.forEach(e => { e.getComponent(cc.Button).interactable = true });
        //方块数据数组
        this.blockDataList = [];
        //方块节点数组
        this.blockNodeList = [];
        //总方片数
        this.totalBlockNum = undefined;
        //删除方片数
        this.removeBlockNum = 0;
        this.isGameOver = false;
        //缓存区方块数组,一栋一栋的设计，方便计算遮挡关系。
        this.bufferList = [[], [], []];
        //初始化网格遮挡关系数据
        this.coverMap = [];  //16 * 20  下表0-15  0-19
        for (let i = 0; i < globalThis.GAME_GLOBAL.levelData["heightNum"] * 2; i++) {
            this.coverMap[i] = [];
            for (let j = 0; j < globalThis.GAME_GLOBAL.levelData["widthNum"] * 2; j++) {
                //默认值为0，代表的时该处格子上方覆盖的方块层数
                this.coverMap[i][j] = 0;
            }
        }
        //回收列表的顺序
        this.lastBlockIndex = -1;
        //方块的回收列表
        this.recycleList = [];
        this.initMapArea();
        this.initBlockData();
        this.creatBlockByData();
        this.setBlockState();
        if (globalThis.GAME_GLOBAL.levelGrade === 1) {
            SoundManager.Instance.playEffect(SoundName.gamestart, 1);
        }
    }

    //初始化摆放区域及基准点
    initMapArea() {
        let s = cc.size(this.gridPre.data.width, this.gridPre.data.height);
        this.mapArea.setContentSize(s.width * globalThis.GAME_GLOBAL.levelData["widthNum"], s.height * globalThis.GAME_GLOBAL.levelData["heightNum"]);
        globalThis.GAME_GLOBAL.rowGap = s.height / 8;
        globalThis.GAME_GLOBAL.lineGap = s.width / 8;
        //确定摆放基准点
        this.basePoint = cc.v2(-(this.mapArea.width - s.width) / 2, (this.mapArea.height - s.height) / 2);
        //播放背景音乐
        this.scheduleOnce(() => { SoundManager.Instance.playMusic(SoundName.bgm_long, 0.2) }, 1.5);
    }

    //创建方片摆放区域地图
    initBlockData() {
        let typeList = [];
        //
        for (let i = 0; i < globalThis.GAME_GLOBAL.levelData["blockTypeDataKey"].length; i++) {
            const type = globalThis.GAME_GLOBAL.levelData["blockTypeDataKey"][i];
            const num = globalThis.GAME_GLOBAL.levelData["blockTypeDataValue"][i];
            //要乘以3，确保方块数量是3的整数倍
            for (let i = 0; i < num * 3; i++) {
                typeList.push(type);
            }
        }
        // for (let key in globalThis.GAME_GLOBAL.levelData["blockTypeData"]) {
        //     let type = parseInt(key);
        //     let num = parseInt(globalThis.GAME_GLOBAL.levelData["blockTypeData"][key]);
        //     //要乘以3，确保方块数量是3的整数倍
        //     for (let i = 0; i < num * 3; i++) {
        //         typeList.push(type);
        //     }
        // }
        this.totalBlockNum = typeList.length;
        //打乱
        typeList.sort(() => { return Math.random() - 0.5; });
        if (globalThis.GAME_GLOBAL.levelGrade > 1) console.log("今日关卡一共有" + this.totalBlockNum + "张牌");
        this.reflushTxt();
        //数据分配
        let index = 0;
        for (let key in globalThis.GAME_GLOBAL.levelData["levelData"]) {
            let list = globalThis.GAME_GLOBAL.levelData["levelData"][key];
            this.blockDataList.push(list);
            for (let i = 0; i < list.length; i++) {
                list[i]["type"] = typeList[index];
                index += 1;
            }
        }
    }

    //创建方块 rolNum列数， rowNum表示行数
    creatBlockByData() {
        let index = 0;
        for (let i = 0; i < this.blockDataList.length; i++) {
            //for(let i = 0; i < 1; i++){  // 测试用 --yyyy
            this.blockNodeList[i] = [];
            for (let j = 0; j < this.blockDataList[i].length; j++) {
                let data = this.blockDataList[i][j];
                let grid = cc.instantiate(this.gridPre);
                let x = this.basePoint.x + parseInt(data["rolNum"]) * globalThis.GAME_GLOBAL.lineGap;
                let y = this.basePoint.y - parseInt(data["rowNum"]) * globalThis.GAME_GLOBAL.rowGap;
                //纵向有偏移量
                y += Math.floor(parseInt(data["rowNum"]) / 8) * globalThis.GAME_GLOBAL.offsetY;
                grid.setPosition(cc.v2(x, y));
                //设置皮肤
                //data["type"] = 13; //--yyyy
                let skin = this.skinList.getSpriteFrame(`block (${data["type"]})`);
                let skinNode = grid.getChildByName("skin");
                skinNode.getComponent(cc.Sprite).spriteFrame = skin;
                //添加至方块节点管理数组
                this.blockNodeList[i][j] = grid;
                //初始化方块对象
                grid.getComponent(Block).init(data, [i, j], cc.v2(x, y), this.coverMap);
                //默认的后来居上不影响遮挡问题，但是撤回的方块会显示在最上，上下相邻方块的咬合效果无法体现
                grid.zIndex = index++;
                this.mapArea.addChild(grid);
            }
        }
    }

    //刷新遮挡层数据 (上左， 上右， 下左， 下右)
    flushCoverMap(index: number[][], value: number) {
        this.coverMap[index[0][0]][index[0][1]] += value;
        this.coverMap[index[1][0]][index[1][1]] += value;
        this.coverMap[index[2][0]][index[2][1]] += value;
        this.coverMap[index[3][0]][index[3][1]] += value;
    }

    //检测方块状态
    setBlockState() {
        for (let i = 0; i < this.blockNodeList.length; i++) {
            for (let j = 0; j < this.blockNodeList[i].length; j++) {
                let blockNode = this.blockNodeList[i][j];
                if (!blockNode) continue;
                let blockObj = blockNode.getComponent(Block);
                let list1 = blockObj.layerOnGrid;
                let list2 = blockObj.baseGridList;
                if (blockObj.moldType === 1 || blockObj.moldType === 2) {
                    let v1 = list1[0] - this.coverMap[list2[0][0]][list2[0][1]];
                    let v2 = list1[1] - this.coverMap[list2[1][0]][list2[1][1]];
                    let v3 = list1[2] - this.coverMap[list2[2][0]][list2[2][1]];
                    let v4 = list1[3] - this.coverMap[list2[3][0]][list2[3][1]];
                    if (v1 < 0 || v2 < 0 || v3 < 0 || v4 < 0) {
                        blockObj.isClosed = true;
                    } else {
                        blockObj.isClosed = false;
                    }
                }
            }
        }
    }

    //地图区域方块被点击
    onBlockInMapClicked(block: Block) {
        if (this.recycleList.length === 7) return false;
        //点击音效
        SoundManager.Instance.playEffect(SoundName.clickEffect, 1);
        //抹除当前方块在方块队列中数据（注意不是直接剔除，否则其它方块坐标会产生漂移）
        this.blockNodeList[block.indexInList[0]][block.indexInList[1]] = null;
        //刷新覆盖层数据
        this.flushCoverMap(block.baseGridList, -1);
        //设置剩余方块显示状态
        this.setBlockState();
        //放入回收区域
        this.insertBlockToRecycleList(block);
        return true;
    }

    //缓冲区区域方块被点击
    onBlockInBufferClicked(block: Block) {
        if (this.recycleList.length === 7) return false;
        SoundManager.Instance.playEffect(SoundName.clickEffect, 1);
        //直接从缓存区拿掉
        this.bufferList[block.indexOfBuffer[0]].pop();
        //刷新缓存区
        this.flushBufferArea();
        //放入回收区域
        this.insertBlockToRecycleList(block);
        return true;
    }

    //将方块插入回收区域
    insertBlockToRecycleList(block: Block) {
        Utils.Instance.changeParentNode(block.node, this.recycleBoard)
        let insertIndex = undefined;
        for (let i = this.recycleList.length - 1; i >= 0; i--) {
            if (block.type === this.recycleList[i].type) {
                insertIndex = i + 1; //匹配成功则，更新插入位置,不加1就会插到相同方块的前面去
                break;
            }
        }
        /*
         * 没匹配上：
         * 1。队列为空，此时下标设置为0； 
         * 2，队列不为空，假设有5个，但没有与之相同的，此时下标设置为5，即加在队尾。
         */
        if (insertIndex === undefined) {
            this.recycleList.push(block);
        } else {
            this.recycleList.splice(insertIndex, 0, block);
        }
        insertIndex = this.recycleList.indexOf(block);
        this.lastBlockIndex = insertIndex;
        this.flushRecycleArea(insertIndex + 1);
        let v = cc.v2(this.recyclePoint.x + insertIndex * (globalThis.GAME_GLOBAL.placeGap + block.node.width), this.recyclePoint.y);
        let moveTime = cc.Vec2.distance(block.node.getPosition(), v) / globalThis.GAME_GLOBAL.moveSpeed;
        this.scheduleOnce(() => { this.checkAndKill() }, moveTime * 1.1);
        cc.tween(block.node)
            .to(moveTime, { position: cc.v3(v) })
            .call(() => {
                block.isMoveTarget = true;
                this.isCanRevocation = true;
            })
            .start();
    }

    //消除和死亡检测
    checkAndKill() {
        if (this.recycleList.length < 3) return;
        //三消检测
        let m = 1;
        let type = this.recycleList[0].type;
        for (let i = 1; i < this.recycleList.length; i++) {
            if (type === this.recycleList[i].type) {
                m += 1;
                if (m === 3) {
                    this.recycleList[i].getComponent(Block).isDestroy = true;
                    this.recycleList[i - 1].getComponent(Block).isDestroy = true;
                    this.recycleList[i - 2].getComponent(Block).isDestroy = true;
                    this.recycleList.splice(i - 2, 3);
                    SoundManager.Instance.playEffect(SoundName.removeEffect, 1);
                    //点下来的这一张如果被消除了，撤销是用不了的
                    this.lastBlockIndex = -1;
                    this.removeBlockNum += 3;
                    this.reflushTxt();
                    break;
                }
            } else {
                m = 1;
                type = this.recycleList[i].type;
            }
        }
        //胜利判断
        if (this.recycleList.length === 0 && this.mapArea.childrenCount === 0) {
            globalThis.GAME_GLOBAL.levelGrade = 2;
            // this.mapArea.x = 1000;
            this.levelLog.spriteFrame = this.levelFrames[globalThis.GAME_GLOBAL.levelGrade - 1];
            this.levelLog.node.setPosition(cc.Vec2.ZERO);
            this.levelLog.node.scale = 2;
            cc.tween(this.levelLog.node)
                .to(0.5, { scale: 1 })
                .to(0.5, { position: cc.v3(0, this.levelLogoPosY, 0) })
                .delay(1)
                .call(() => { this.restartGame() })
                .start()
            cc.tween(this.DifficultyTxtNode)
                .delay(1)
                .to(0, { opacity: 255 })
                .delay(0.5)
                .to(0.5, { opacity: 0 })
                .start()
        }
        //三消后移动补空
        if (m === 3) {
            this.flushRecycleArea(0);
            return;
        }
        //死亡判断
        if (this.recycleList.length === 7) {
            this.onGameOver();
        }
    }

    //拿出三块道具
    onButtonTakeOutClicked(event: cc.Event.EventTouch) {
        //没三张牌，用个锤子的道具
        if (this.recycleList.length < 3) {
            console.log("待消除区域没有三张牌");
            return;
        }
        SoundManager.Instance.playEffect(SoundName.clickEffect, 1);
        event.target.getComponent(cc.Button).interactable = false;
        SDKHelper.Instance.showRewardVideo({
            success: () => {
                this.isCanRevocation = false;
                //从回收区移动至缓存区
                let list = this.recycleList.splice(0, 3);
                //如果最后一张被点击的牌被拿上去了，那么是无法撤退的
                if (this.lastBlockIndex < 3) {
                    this.lastBlockIndex = -1;
                }
                //刷新回收区
                this.flushRecycleArea(0);
                //拿出的方块移动至缓存区
                for (let i = 0; i < list.length; i++) {
                    this.bufferList[i].push(list[i]);
                    list[i].indexOfBuffer = [i, this.bufferList[i].length - 1];
                    list[i].node.zIndex += this.bufferList[i].length - 1;
                    //修改父节点并,重新设置坐标,保持显示位置不改变
                    Utils.Instance.changeParentNode(list[i].node, this.bufferArea);
                    //移动至目标位置
                    let pos = cc.v2((list[i].node.width + globalThis.GAME_GLOBAL.placeGap) * (i - 1), list[i].indexOfBuffer[1] * list[i].node.height / 8);
                    let t = cc.Vec2.distance(list[i].node.getPosition(), pos) / globalThis.GAME_GLOBAL.moveSpeed;
                    list[i].node.zIndex = this.bufferList.length;
                    cc.tween(list[i].node)
                        .to(t, { position: cc.v3(pos) })
                        .call(() => {
                            list[i].isInBuffer = true;
                            //设置为密集排列类型
                            list[i].moldType = 2;
                            //更新原始坐标
                            list[i].originalPos = pos;
                            //刷新缓冲区
                            this.flushBufferArea();
                        })
                        .start();
                }
            },
            fail: () => {
                event.target.getComponent(cc.Button).interactable = true;
            }
        })
    }

    //撤退道具
    onButtonRetreatClicked(event: cc.Event.EventTouch) {
        if (!this.isCanRevocation) {
            console.log("没有可以撤回的牌");
            return;
        }
        SoundManager.Instance.playEffect(SoundName.clickEffect, 1);
        if (this.recycleList.length === 0 || this.lastBlockIndex === -1) return;
        event.target.getComponent(cc.Button).interactable = false;
        SDKHelper.Instance.showRewardVideo({
            success: () => {
                let block = this.recycleList.splice(this.lastBlockIndex, 1)[0];
                //移动补空
                this.flushRecycleArea(this.lastBlockIndex);
                //返回方块节点列表
                if (block.isInBuffer) {
                    this.bufferList[block.indexOfBuffer[0]][block.indexOfBuffer[1]] = block;
                    block.goBack(this.bufferArea);
                } else {
                    this.blockNodeList[block.indexInList[0]][block.indexInList[1]] = block.node;
                    block.goBack(this.mapArea);
                }
                //暂时设计为不能连续使用 --yyyy
                this.lastBlockIndex = -1;
            },
            fail: () => {
                event.target.getComponent(cc.Button).interactable = true;
            }
        })
    }

    //洗牌道具
    onButtonReshuffleClicked(event: cc.Event.EventTouch) {
        if (this.mapArea.children.length == 0) return;
        event.target.getComponent(cc.Button).interactable = false;
        SoundManager.Instance.playEffect(SoundName.clickEffect, 1);
        SDKHelper.Instance.showRewardVideo({
            success: () => {
                //启用全屏遮罩
                this.mask.active = true;
                //将所有的牌搜集到一起
                let blockList = this.mapArea.children;
                let angerGap = 360 / blockList.length;
                let vecStd = cc.v2(0, 200);
                //改变所有牌的父节点
                for (let i = 0; i < blockList.length; i++) {
                    let block = blockList[i];
                    cc.tween(block)
                        //这里不知道为何，y方向上需要做偏移？？？？？ --yyyy
                        .to(0.2, { position: cc.v3(0, 45, 0), angle: -angerGap * i })
                        .delay(0.1)
                        .to(0.3, { position: cc.v3(vecStd.rotate((angerGap * i * Math.PI) / 180).add(cc.v2(0, 45))) })
                        .delay(0.1)
                        .call(() => {
                            SoundManager.Instance.playEffect(SoundName.shuffleEffect, 0.05);
                            this.changeSkinOfAllBlock();
                            Utils.Instance.changeParentNode(block, this.shuffleNode);
                            cc.tween(this.shuffleNode).by(1, { angle: -360 * 4 }).start();
                        })
                        .delay(1.1)
                        .call(() => { Utils.Instance.changeParentNode(block, this.mapArea) })
                        .to(0.2, { position: cc.v3(block.getComponent(Block).originalPos), angle: 0 })
                        .call(() => { this.mask.active = false })
                        .start();
                }
            },
            fail: () => {
                event.target.getComponent(cc.Button).interactable = true;
            }
        })

    }

    //随机打乱皮肤
    changeSkinOfAllBlock() {
        //将所有的牌搜集到一起
        let blockList = this.mapArea.children;
        //将皮肤拿到
        let skinList = (function () {
            let arr = [];
            blockList.forEach(node => {
                arr.push(node.getComponent(Block).type);
            })
            return arr;
        })();
        //将皮肤打乱
        skinList.sort((a, b) => { return Math.random() - 0.5 });
        //重新分配皮肤并刷新
        for (let i = 0; i < blockList.length; i++) {
            let block = blockList[i].getComponent(Block);
            //修改type属性
            block.type = skinList[i];
            //刷新皮肤
            block.skin.getComponent(cc.Sprite).spriteFrame = this.skinList.getSpriteFrame(`block (${block.type})`);
        }
    }

    //刷新回收区
    flushRecycleArea(startIndex: number) {
        for (let i = startIndex; i < this.recycleList.length; i++) {
            //防止坐标迷失飘逸，AABC， 快速点击A D时，A的初始目标槽位是3，D是5，但是A到位后会删除，此时D的目标槽又5更新为3,如果它还在半道上，就GG了。
            //this.recycleList[i].node.stopAllActions();  //缩放的动作不能停
            this.recycleList[i].node.stopActionByTag(1001);
            //计算移动时间
            let targetPos = cc.v2(this.recyclePoint.x + i * (globalThis.GAME_GLOBAL.placeGap + this.recycleList[i].node.width), this.recyclePoint.y);
            let currentPos = this.recycleList[i].node.getPosition();
            let moveTime = cc.Vec2.distance(targetPos, currentPos) / globalThis.GAME_GLOBAL.moveSpeed;
            cc.tween(this.recycleList[i].node).to(moveTime, { position: cc.v3(targetPos) }).start();
        }
    }

    //刷新缓冲区
    flushBufferArea() {
        //从最上面一层开始检查，以列为单位从上至下扫描，短路检测法，提高效率
        for (let i = 0; i < this.bufferList.length; i++) {
            for (let j = this.bufferList[i].length - 1; j >= 0; j--) {
                if (this.bufferList[i][j]) {
                    if (j === this.bufferList[i].length - 1) {
                        this.bufferList[i][j].isClosed = false;
                        this.bufferList[i][j].isClicked = false;
                    } else {
                        this.bufferList[i][j].isClosed = true;
                        this.bufferList[i][j].isClicked = true;
                    }
                }
            }
        }
    }

    //刷新计数文本显示
    reflushTxt() {
        let str = `总数：${this.totalBlockNum}  消除： ${this.removeBlockNum}  剩余：${this.totalBlockNum - this.removeBlockNum} `;
        this.countTxt.string = str;
    }

    //游戏结束
    onGameOver() {
        this.isGameOver = true;
        EventManager.Instance.emit(Event_Name.LAYER_CHANGE, LAYER_CHANGE_TYPE.GAME_TO_OVER);
    }

    //重新开始
    restartGame() {
        //删除主场与回收区域的方块    --todo  使用道具后的暂存区
        this.mapArea.children.forEach(node => {
            node.destroy();
        })
        this.recycleBoard.children.forEach(node => {
            node.destroy();
        })
        this.bufferArea.children.forEach(node => {
            node.destroy();
        })
        //结束层隐藏
        this.gameoverLayer.active = false;
        this.initLevelData();
    }

}
